#include "sdlwindow.h"
#include "utils.h"
#include <GL/gl.h>
#include <QDebug>

const double SDLWindow::sceneWidth_ = 1000.0;
const double SDLWindow::sceneHeight_ = 100.0;

SDLWindow::SDLWindow() : terrain_(sceneWidth_), projectile_(NULL), winWidth_(800), winHeight_(600), cameraPosX_(0.0), cameraPosY_(0.0)
{
    int ret = SDL_Init(SDL_INIT_VIDEO);
    if(ret < 0) {
    }

    surface_ = SDL_SetVideoMode(winWidth_, winHeight_, 32, SDL_HWSURFACE | SDL_RESIZABLE | SDL_OPENGL | SDL_DOUBLEBUF);

    glClearColor(.0, .2, .3, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    scaleFactorX_ = sceneWidth_ / (double)winWidth_;
    scaleFactorY_ = sceneHeight_ / (double)winHeight_;

    double fillFactor;
    if(winWidth_ > winHeight_) {
        fillFactor = (double)winWidth_ / sceneWidth_;
    } else {
        fillFactor = (double)winHeight_ / sceneHeight_;
    }

    scaleFactorX_ *= fillFactor;
    scaleFactorY_ *= fillFactor;

    maxZoomOutFactorX_ = scaleFactorX_;
    maxZoomOutFactorY_ = scaleFactorY_;

    setProjection();

    Utils::designatePlayerPosition(player_, sceneWidth_);
}

SDLWindow::~SDLWindow()
{
    SDL_Quit();
}

int SDLWindow::exec()
{
    SDL_Event event;
    while(SDL_WaitEvent(&event))
    {
        if(event.type == SDL_QUIT)
        {
            break;
        }
        else if(event.type == SDL_KEYDOWN)
        {
            if(event.key.keysym.sym == SDLK_ESCAPE)
            {
                break;
            }
            else if(event.key.keysym.sym == SDLK_SPACE)
            {
                projectile_.reset(player_.fire(sceneWidth_));
            }
            else if(event.key.keysym.mod & KMOD_CTRL)
            {
                processCameraEvent(event);
            }
            else
            {
                processPlayerEvent(event);
            }
        }

        render();
    }

    return 0;
}

void SDLWindow::render()
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glClear(GL_COLOR_BUFFER_BIT);

    terrain_.render();

    //Utils::renderMesh(100, winWidth_, winHeight_);

    player_.render();

    if(projectile_.get() != NULL) {
        projectile_->render();
    }

    SDL_GL_SwapBuffers();
}

void SDLWindow::processCameraEvent(SDL_Event &event)
{
    switch(event.key.keysym.sym)
    {
        case SDLK_PLUS:
        case SDLK_KP_PLUS:
            scaleFactorX_ *= zoomStep_;
            scaleFactorY_ *= zoomStep_;
            break;
        case SDLK_MINUS:
        case SDLK_KP_MINUS:
            scaleFactorX_ /= zoomStep_;
            scaleFactorY_ /= zoomStep_;
            if(scaleFactorX_ < maxZoomOutFactorX_ || scaleFactorY_ < maxZoomOutFactorY_)
            {
                scaleFactorX_ = maxZoomOutFactorX_;
                scaleFactorY_ = maxZoomOutFactorY_;
            }
             break;
        case SDLK_LEFT:
            cameraPosX_ += cameraMoveStep_;
            break;
        case SDLK_RIGHT:
            cameraPosX_ -= cameraMoveStep_;
            break;
        case SDLK_UP:
            cameraPosY_ -= cameraMoveStep_;
            break;
        case SDLK_DOWN:
            cameraPosY_ += cameraMoveStep_;
            break;
        default:
            break;
    }

    setProjection();
}

void SDLWindow::processPlayerEvent(SDL_Event &event)
{
    bool shifted = event.key.keysym.mod & KMOD_SHIFT;
    switch(event.key.keysym.sym)
    {
        case SDLK_UP:
            player_.increaseAngle(shifted);
            break;
        case SDLK_DOWN:
            player_.decreaseAngle(shifted);
            break;
        default:
            break;
    }
}

void SDLWindow::setProjection()
{
    qDebug() << "Current scale factors: " << scaleFactorX_ << " " << scaleFactorY_;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-sceneWidth_/2.0, sceneWidth_/2.0, -sceneHeight_/2.0, sceneHeight_/2.0,
            -1.0, 1.0);
    glScaled(scaleFactorX_, scaleFactorY_, 1.0);
    glTranslated(cameraPosX_, cameraPosY_, 0.0);
}
